#include "asm_utils.h"
#include "interrupt.h"
#include "stdio.h"
#include "program.h"
#include "thread.h"
#include "sync.h"

// 屏幕IO处理器
STDIO stdio;
// 中断管理器
InterruptManager interruptManager;
// 程序管理器
ProgramManager programManager;

Semaphore chopstick[5];

int cheese_burger;

void philosopher_one(void *arg)
{
 int delay = 0xf;
 while(1){
     while (delay)
        --delay;
    printf("number 1: I am hungry\n");
    chopstick[0].P();//把筷子摁住，此时别人拿不起来这一根了
    delay=0xfffffff;//这里让筷子只拿起一根，引发死锁
     while (delay)
        --delay;
    chopstick[1].P();
   

    printf("number 1: I am eating now.\n");
    delay = 0xfffffff;
    while (delay)
        --delay;
    // done

    printf("number 1 :I am full, now I should think.\n");
    chopstick[0].V();//把筷子还给别人
    chopstick[1].V();
    delay=0xfffffff;//记得恢复
    }
}

void philosopher_two(void *arg)
{
    int delay =0xf;
    while(1){
    while (delay)
        --delay;
    printf("number 2: I am hungry\n");

    chopstick[1].P();//把筷子摁住，此时别人拿不起来这一根了
    delay=0xfffffff;//这里让筷子只拿起一根，引发死锁
     while (delay)
        --delay;
    chopstick[2].P();
    

    printf("number 2: I am eating now.\n");
    delay = 0xfffffff;
    while (delay)
        --delay;
    // done

    printf("number 2 :I am full, now I should think.\n");
    chopstick[1].V();//把筷子还给别人
    chopstick[2].V();
    delay=0xfffffff;//记得恢复
    }
}

void philosopher_three(void *arg)
{
    int delay =0xf;
    while(1){
        while (delay)
        --delay;
    printf("number 3: I am hungry\n");
    chopstick[2].P();//把筷子摁住，此时别人拿不起来这一根了
    delay=0xfffffff;//这里让筷子只拿起一根，引发死锁
     while (delay)
        --delay;
    chopstick[3].P();

    printf("number 3: I am eating now.\n");
    delay = 0xfffffff;
    while (delay)
        --delay;
    // done

    printf("number 3 :I am full, now I should think.\n");
    chopstick[2].V();//把筷子还给别人
    chopstick[3].V();
    delay=0xfffffff;//记得恢复
    }
}

void philosopher_four(void *arg)
{
   int delay=0xf;
    while(1){
       while (delay)
        --delay;
    printf("number 4: I am hungry\n");
    chopstick[3].P();//把筷子摁住，此时别人拿不起来这一根了
    delay=0xfffffff;//这里让筷子只拿起一根，引发死锁
     while (delay)
        --delay;
    chopstick[4].P();


    printf("number 4: I am eating now.\n");
    delay = 0xfffffff;
    while (delay)
        --delay;
    // done

    printf("number 4 :I am full, now I should think.\n");
    chopstick[3].V();//把筷子还给别人
    chopstick[4].V();
    delay=0xfffffff;//记得恢复
    }
}

void philosopher_five(void *arg)
{
     int delay = 0xf;
    while(1){
       while (delay)
        --delay;
    printf("number 5: I am hungry\n");
    chopstick[4].P();//把筷子摁住，此时别人拿不起来这一根了
    delay=0xfffffff;//这里让筷子只拿起一根，引发死锁
     while (delay)
        --delay;
    chopstick[0].P();
   

    printf("number 5: I am eating now.\n");
    delay = 0xfffffff;
    while (delay)
        --delay;
    // done

    printf("number 5 :I am full, now I should think.\n");
    chopstick[4].V();//把筷子还给别人
    chopstick[0].V();
    delay=0xfffffff;//记得恢复
    }
}


void first_thread(void *arg)
{
    // 第1个线程不可以返回
    stdio.moveCursor(0);
    for (int i = 0; i < 25 * 80; ++i)
    {
        stdio.print(' ');
    }
    stdio.moveCursor(0);

    cheese_burger = 0;
    for(int i=0; i<5;i++)
    {
      chopstick[i].initialize(1);//创建资源
    }
    

    programManager.executeThread(philosopher_one, nullptr, "second thread", 1);
    programManager.executeThread(philosopher_two, nullptr, "third thread", 1);
    programManager.executeThread(philosopher_three, nullptr, "fourth thread", 1);
    programManager.executeThread(philosopher_four, nullptr, "fifth thread", 1);
    programManager.executeThread(philosopher_five, nullptr, "sixth thread", 1);

    asm_halt();
}

extern "C" void setup_kernel()
{

    // 中断管理器
    interruptManager.initialize();
    interruptManager.enableTimeInterrupt();
    interruptManager.setTimeInterrupt((void *)asm_time_interrupt_handler);

    // 输出管理器
    stdio.initialize();

    // 进程/线程管理器
    programManager.initialize();

    // 创建第一个线程
    int pid = programManager.executeThread(first_thread, nullptr, "first thread", 1);
    if (pid == -1)
    {
        printf("can not execute thread\n");
        asm_halt();
    }

    ListItem *item = programManager.readyPrograms.front();
    PCB *firstThread = ListItem2PCB(item, tagInGeneralList);
    firstThread->status = RUNNING;
    programManager.readyPrograms.pop_front();
    programManager.running = firstThread;
    asm_switch_thread(0, firstThread);

    asm_halt();
}
